"""
    timetable service
"""

import time
import os
import pandas as pd
from bs4.element import Tag
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.support.select import Select
from selenium.common.exceptions import NoAlertPresentException

# 课表位置索引
index_table = {'1': 2, '3': 4, '6': 7, '8': 9, '10': 11}


def recognize_captcha(chrome):
    """
    验证码识别
    :param chrome: webdriver
    :return: None
    """
    with open('zf.js', 'r', encoding='utf-8') as fp:
        js = fp.read()
        chrome.execute_script(js)


def wait_response(chrome, selector):
    """
    等待页面响应
    :param chrome: webdriver
    :param selector: css 选择器
    :return: None
    """
    while True:
        try:
            chrome.find_element_by_css_selector(selector)
            break
        except Exception:
            time.sleep(1)


def have_alter(chrome):
    """
    当前是否有 alter 弹窗，若有关闭返回弹窗内容，否则返回 None
    :param chrome: webdriver
    :return: 弹窗内容
    """
    current = chrome.current_window_handle
    try:
        alert = chrome.switch_to.alert
        alert.accept()
        return alert.text
    except NoAlertPresentException:
        return None
    finally:
        chrome.switch_to.window(current)


def have_element(chrome, selector) -> str:
    """
    返回有无元素
    :param chrome: webdriver
    :param selector: 选择器
    :return: bool
    """
    try:
        chrome.find_element_by_css_selector(selector)
        return True
    except Exception:
        return False


def enter_info(chrome, username, password):
    """
    输入用户信息
    :param chrome: webdriver
    :param username: 学号
    :param password: 密码
    :return: None
    """
    # 输入学号
    username_input = chrome.find_element_by_id("txtUserName")
    username_input.clear()
    username_input.send_keys(username)

    # 输入密码
    password_input = chrome.find_element_by_id("TextBox2")
    password_input.clear()
    password_input.send_keys(password)


def get_timetable_page(chrome, term, year, name, username, password) -> str:
    """
    获取课表页面资源
    :param year: 学年
    :param term: 学期
    :param name: 姓名
    :param username: 学号
    :param password: 密码
    :param chrome: webdriver
    :return: 课表页面 HTML
    """
    recognize_captcha(chrome)  # 识别验证码
    enter_info(chrome, username, password)  # 输入信息

    # 等待验证码识别
    get_captcha_js = "return document.getElementById('txtSecretCode').value"
    captcha = chrome.execute_script(get_captcha_js)
    while captcha.strip() == '':
        time.sleep(1)
        captcha = chrome.execute_script(get_captcha_js)

    # 点击登录
    chrome.find_element_by_id("Button1").click()

    # 判断验证码是否正确
    alert_text = have_alter(chrome)
    reload_msg = ['验证码不正确！！', '验证码不能为空，如看不清请刷新！！']
    while alert_text in reload_msg:
        chrome.get("http://10.10.10.71/default2.aspx")
        recognize_captcha(chrome)  # 识别验证码
        enter_info(chrome, username, password)  # 输入信息
        chrome.find_element_by_id("Button1").click()
    
    # 其他错误消息
    error_msg = ['用户名不能为空！！', '密码不能为空！！', '密码错误！！', '用户名不存在或未按照要求参加教学活动！！']
    if alert_text in error_msg:
        raise Exception(alert_text)

    # 访问课表页面
    chrome.execute_script('window.open("http://10.10.10.71/xskbcx.aspx?xh={0}&xm={1}");'.format(username, name))

    # 切换到新开页面
    main_window = chrome.current_window_handle
    for window in chrome.window_handles:
        if window != main_window:
            chrome.switch_to.window(window)

    # 等待响应
    wait_response(chrome, "#xskb_form > div > div > span > table.blacktab")

    # 若出现弹窗则关闭
    have_alter(chrome)

    # 选择时间段
    Select(chrome.find_element_by_css_selector("#xnd")).select_by_value(year)
    have_alter(chrome)
    Select(chrome.find_element_by_css_selector("#xqd")).select_by_value(term)
    have_alter(chrome)

    # 获取页面资源
    page_source = chrome.page_source

    chrome.close()
    chrome.switch_to.window(main_window)
    return page_source


def parse_timetable(page_source) -> dict:
    """
    解析课表
    :param page_source: 课表页源代码
    :return: 课表字典
    """
    # 课表容器
    time_table = {'1': None, '3': None, '6': None, '8': None, '10': None}

    # 课表行
    tr_list = BeautifulSoup(page_source, 'lxml').select('#Table1 tr')
    for k, v in index_table.items():
        td_list = tr_list[index_table[k]].select('td')

        # 数据起始下标
        start_idx = 1 if td_list[0].get_text(strip=True) not in ('上午', '下午', '晚上') else 2

        line = []  # 解析行容器
        for i in range(start_idx, len(td_list)):
            td = td_list[i]

            if td.get_text(strip=True) != '':
                section = int(td['rowspan'])  # 节数
                course = '#'.join(list(filter(lambda x: not isinstance(x, Tag), td.contents)))  # 课程信息
                line.append([course, section])
            else:
                line.append(None)  # 无课

        time_table[k] = line  # 存储课表容器

    # 5, 6, 7 节特殊处理
    td_list = tr_list[6].select('td')
    for i in range(2, len(td_list)):
        if td_list[i].get_text(strip=True) != '':
            time_table['6'][i - 2][1] = 3

    return time_table


def write_in_excel(filename, time_table, sep='&'):
    """
    将数据写入 excel
    :param sep: 数据之间分隔符
    :param filename: 文件路径
    :param time_table: 课表数据
    :return: None
    """
    # 初始化课表
    origin_df = None
    have_origin = False
    if os.path.exists(filename):
        have_origin = True
        origin_df = pd.read_excel(filename, index_col=0)
        origin_df.fillna('', inplace=True)

    # 操作表
    if have_origin:
        df = origin_df.copy()
    else:
        df = pd.DataFrame(
            {'周一': [''] * 12, '周二': [''] * 12, '周三': [''] * 12, '周四': [''] * 12, '周五': [''] * 12, '周六': [''] * 12,
             '周日': [''] * 12})
        df.index = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

    for k, v in time_table.items():
        for i, c in enumerate(time_table[k]):
            if c is None:
                continue  # 无课

            start_idx = 5 if k == '6' and c[1] == 3 else int(k)
            end_idx = start_idx + c[1]

            for j in range(start_idx, end_idx):
                if have_origin:
                    df.iloc[j - 1, i] = origin_df.iloc[j - 1, i] + c[0] + sep
                else:
                    df.loc[j][i] = c[0] + sep

    df.to_excel(filename)